#pragma once

#include <ctime>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>

static const int gcap = 5; // 环形队列的容量

template <class T>

class RingQueue
{
private:
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);
        (void)n;
    }
    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }

    //  public 公共成员变量
public:
    // 初始化这个类
    RingQueue(const int &cap = gcap) : _queue(cap), _cap(cap)
    {
        // 类里面定义了信号量，但是还得的初始化信号量
        sem_init(&_spaceSem, 0, _cap);
        sem_init(&_dataSem, 0, 0);
        _procuctorStep = 0;
        _consumerStep = 0;
    }
    void Push(const T &in)
    {
        P(_spaceSem); // 申请到了空间信号量，意味着我，一定能进行正常的生产
        _queue[_procuctorStep++] = in; // 生产的位置
        _procuctorStep %= _cap;  // 要模拟环形队列，所以需要%，一直在5以内生产
        V(_dataSem);
    }
    void Pop(T *out)
    {
        P(_dataSem);
        *out = _queue[_consumerStep++];
        _consumerStep %= _cap;
        V(_spaceSem);
    }
    // 析构函数，于在对象销毁时执行清理工作
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
    }
    // 私有
private:
    std::vector<T> _queue;
    int _cap;        // 队列的容量
    sem_t _spaceSem; // 生产者的信号量  空间资源
    sem_t _dataSem;  // 消费者信号量    数据资源
    int _procuctorStep; // 生产者的下标
    int _consumerStep;  // 消费这的下标
    // 保护
protected:
};
